package com.share.thread;

import org.apache.commons.lang3.RandomUtils;


/**
 * @desc: 哲学家就餐问题
 * @author:caifan
 * @date:2022/4/8
 */
public class DiningPhilosophers {

    /**
     * 哲学家
     * 在创建这个哲学家实例，也就是调用构造方法的时候，需要传入两个参数，分别是左手的筷子和右手的筷子
     */
    public static class Philosopher implements Runnable {

        private Object leftChopstick;
        private Object rightChopstick;

        public Philosopher(Object leftChopstick, Object rightChopstick) {
            this.leftChopstick = leftChopstick;
            this.rightChopstick = rightChopstick;
        }

        @Override
        public void run() {

            try {
                // 思考
                doAction("思考");

                synchronized (leftChopstick) {
                    // 拿左筷子
                    doAction("拿左筷子");
                    synchronized (rightChopstick) {
                        // 拿右筷子
                        doAction("右筷子");
                        // 吃饭
                        doAction("吃饭");
                        // 放右筷子
                        doAction("放右筷子");
                    }
                    // 放左筷子
                    doAction("放左筷子");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        /**
         * 这里的随机休眠是为了模拟真实的场景，因为每个哲学家的思考、吃饭和拿筷子的时间会各不相同
         * @param action 动作
         * @throws InterruptedException
         */
        private void doAction(String action) throws InterruptedException {
            System.out.println(Thread.currentThread().getName() + ":" + action);
            Thread.sleep(RandomUtils.nextLong(100, 1000));
        }
    }

    public static void main(String[] args) {
        // 哲学家
        Philosopher[] philosophers = new Philosopher[5];
        // 筷子
        Object[] chopsticks = new Object[philosophers.length];
        for (int i = 0; i < chopsticks.length; i++) {
            chopsticks[i] = new Object();
        }
        for (int i = 0; i < philosophers.length; i++) {
            Object leftChopstick = chopsticks[i];
            Object rightChopstick = chopsticks[(i + 1) % chopsticks.length];
            // 产生死锁
//            philosophers[i] = new Philosopher(rightChopstick, leftChopstick);

            /**
             * 让最后一个人与其他人将锁的方向变化，破坏循环条件可解决死锁问题
             */
            if (i == philosophers.length - 1) {
                philosophers[i] = new Philosopher(rightChopstick, leftChopstick);
            } else {
                philosophers[i] = new Philosopher(leftChopstick, rightChopstick);
            }

            new Thread(philosophers[i], "哲学家" + (i + 1) + "号").start();
        }
    }


}
